﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LEDControllerTools.Controller
{
    internal class ControllerDefinition
    {
        private static ControllerDefinition _definition;

        public string BatteryCommand { get; private set; }
        public IDictionary<string, DigitalOutCommandDefinition> DigitalCommands { get; private set; }

        private ControllerDefinition()
        {
            BatteryCommand = "?";
            DigitalCommands = GetDigitalCommands();
        }
        
        public static ControllerDefinition GetDefinition()
        {
            if (_definition == null)
                _definition = new ControllerDefinition();

            return _definition;
        }

        private IDictionary<string,DigitalOutCommandDefinition> GetDigitalCommands()
        {
            var commands = new Dictionary<string, DigitalOutCommandDefinition>();
            var ports = GetControllerPorts();

            commands.Add("A1", new DigitalOutCommandDefinition {On = "A", Off = "a", WorksWith = new[] {ports["A1"]}});
            commands.Add("A2", new DigitalOutCommandDefinition {On = "B", Off = "b", WorksWith = new[] {ports["A2"]}});
            commands.Add("A3", new DigitalOutCommandDefinition {On = "C", Off = "c", WorksWith = new[] {ports["A3"]}});
            commands.Add("A4", new DigitalOutCommandDefinition {On = "D", Off = "d", WorksWith = new[] {ports["A4"]}});
            commands.Add("A5", new DigitalOutCommandDefinition {On = "E", Off = "e", WorksWith = new[] {ports["A5"]}});
            commands.Add("A6", new DigitalOutCommandDefinition {On = "F", Off = "f", WorksWith = new[] {ports["A6"]}});
            commands.Add("A7", new DigitalOutCommandDefinition {On = "G", Off = "g", WorksWith = new[] {ports["A7"]}});

            commands.Add("B1", new DigitalOutCommandDefinition {On = "H", Off = "h", WorksWith = new[] {ports["B1"]}});
            commands.Add("B2", new DigitalOutCommandDefinition {On = "I", Off = "i", WorksWith = new[] {ports["B2"]}});
            commands.Add("B3", new DigitalOutCommandDefinition {On = "J", Off = "j", WorksWith = new[] {ports["B3"]}});
            commands.Add("B4", new DigitalOutCommandDefinition {On = "K", Off = "k", WorksWith = new[] {ports["B4"]}});
            commands.Add("B5", new DigitalOutCommandDefinition {On = "L", Off = "l", WorksWith = new[] {ports["B5"]}});
            commands.Add("B6", new DigitalOutCommandDefinition {On = "M", Off = "m", WorksWith = new[] {ports["B6"]}});
            commands.Add("B7", new DigitalOutCommandDefinition {On = "N", Off = "n", WorksWith = new[] {ports["B7"]}});

            commands.Add("C1", new DigitalOutCommandDefinition {On = "O", Off = "o", WorksWith = new[] {ports["C1"]}});
            commands.Add("C2", new DigitalOutCommandDefinition {On = "P", Off = "p", WorksWith = new[] {ports["C2"]}});
            commands.Add("C3", new DigitalOutCommandDefinition {On = "Q", Off = "q", WorksWith = new[] {ports["C3"]}});
            commands.Add("C4", new DigitalOutCommandDefinition {On = "R", Off = "r", WorksWith = new[] {ports["C4"]}});
            commands.Add("C5", new DigitalOutCommandDefinition {On = "S", Off = "s", WorksWith = new[] {ports["C5"]}});
            commands.Add("C6", new DigitalOutCommandDefinition {On = "T", Off = "t", WorksWith = new[] {ports["C6"]}});
            commands.Add("C7", new DigitalOutCommandDefinition {On = "U", Off = "u", WorksWith = new[] {ports["C7"]}});

            commands.Add("D1", new DigitalOutCommandDefinition {On = "V", Off = "v", WorksWith = new[] {ports["D1"]}});
            commands.Add("D2", new DigitalOutCommandDefinition {On = "W", Off = "w", WorksWith = new[] {ports["D2"]}});
            commands.Add("D3", new DigitalOutCommandDefinition {On = "X", Off = "x", WorksWith = new[] {ports["D3"]}});
            commands.Add("D4", new DigitalOutCommandDefinition {On = "Y", Off = "y", WorksWith = new[] {ports["D4"]}});
            commands.Add("D5", new DigitalOutCommandDefinition {On = "Z", Off = "z", WorksWith = new[] {ports["D5"]}});
            commands.Add("D6", new DigitalOutCommandDefinition {On = "!", Off = "1", WorksWith = new[] {ports["D6"]}});
            commands.Add("D7", new DigitalOutCommandDefinition {On = "@", Off = "2", WorksWith = new[] {ports["D7"]}});

            commands.Add("A",
                                new DigitalOutCommandDefinition
                                    {
                                        On = ")",
                                        Off = "0",
                                        WorksWith = new[] { ports["A1"], ports["A2"], ports["A3"], ports["A4"], ports["A5"], ports["A6"], ports["A7"] }
                                    });
            commands.Add("B",
                                new DigitalOutCommandDefinition
                                    {
                                        On = "_",
                                        Off = "-",
                                        WorksWith = new[] { ports["B1"], ports["B2"], ports["B3"], ports["B4"], ports["B5"], ports["B6"], ports["B7"] }
                                    });
            commands.Add("C",
                                new DigitalOutCommandDefinition
                                    {
                                        On = "+",
                                        Off = "=",
                                        WorksWith = new[] { ports["C1"], ports["C2"], ports["C3"], ports["C4"], ports["C5"], ports["C6"], ports["C7"] }
                                    });
            commands.Add("D",
                                new DigitalOutCommandDefinition
                                    {
                                        On = "|",
                                        Off = @"\",
                                        WorksWith = new[] { ports["D1"], ports["D2"], ports["D3"], ports["D4"], ports["D5"], ports["D6"], ports["D7"] }
                                    });



            commands.Add("1",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "#",
                                       Off = "3",
                                       WorksWith = new[] {ports["A1"], ports["B1"], ports["C1"], ports["D1"]}
                                   });
            commands.Add("2",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "$",
                                       Off = "4",
                                       WorksWith = new[] {ports["A2"], ports["B2"], ports["C2"], ports["D2"]}
                                   });
            commands.Add("3",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "%",
                                       Off = "5",
                                       WorksWith = new[] {ports["A3"], ports["B3"], ports["C3"], ports["D3"]}
                                   });
            commands.Add("4",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "^",
                                       Off = "6",
                                       WorksWith = new[] {ports["A4"], ports["B4"], ports["C4"], ports["D4"]}
                                   });
            commands.Add("5",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "&",
                                       Off = "7",
                                       WorksWith = new[] {ports["A5"], ports["B5"], ports["C5"], ports["D5"]}
                                   });
            commands.Add("6",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "*",
                                       Off = "8",
                                       WorksWith = new[] {ports["A6"], ports["B6"], ports["C6"], ports["D6"]}
                                   });
            commands.Add("7",
                               new DigitalOutCommandDefinition
                                   {
                                       On = "(",
                                       Off = "9",
                                       WorksWith = new[] {ports["A7"], ports["B7"], ports["C7"], ports["D7"]}
                                   });
            
            commands.Add("All",
                   new DigitalOutCommandDefinition
                   {
                       On = "~",
                       Off = "`",
                       WorksWith = ports.Values.ToArray()
                   });
            return commands;

            
        }


        private Dictionary<string, VirtualPort> GetControllerPorts()
        {
            var portMap = GetPic16F871PortMap();
            return portMap.ToDictionary(port => port.Key, port => new VirtualPort(port.Key, port.Value));
        }

        private Dictionary<string, string> GetPic16F871PortMap()
        {
            // Map of virtual LED Ports to actual PIC microcontroller pins
            var portMap = new Dictionary<string, string>
                {
                    {"A7", "RA1"},
                    {"A6", "RA2"},
                    {"A5", "RA3"},
                    {"A4", "RA4"},
                    {"A3", "RA5"},
                    {"A2", "RE0"},
                    {"A1", "RE1"},
                    {"B7", "RB7"},
                    {"B6", "RB6"},
                    {"B5", "RB5"},
                    {"B4", "RB4"},
                    {"B3", "RB3"},
                    {"B2", "RB2"},
                    {"B1", "RB1"},
                    {"C7", "RC0"},
                    {"C6", "RB1"},
                    {"C5", "RB2"},
                    {"C4", "RB3"},
                    {"C3", "RD0"},
                    {"C2", "RD1"},
                    {"C1", "RD2"},
                    {"D7", "RD6"},
                    {"D6", "RB5"},
                    {"D5", "RB4"},
                    {"D4", "RB3"},
                    {"D3", "RD4"},
                    {"D2", "RC4"},
                    {"D1", "RD3"}
                };

            //var reversedMap = new Dictionary<string, string>();
            //foreach (var kvp in portMap)
            //    portMap.Add(kvp.Value,kvp.Key);

            return portMap;
        }
    }


}
